import os
import time
import wave

import pyaudio
from pydub import AudioSegment

from config import DB_CONFIG

"""
    录制指定时长的音频并保存为WAV格式
    Args:
        filename: 保存的文件名（不含扩展名）
        duration: 录音时长（秒），默认4秒
        
    Returns:
        str: WAV文件路径
"""
def record_audio(filename, duration=4):

    # 音频参数（严格匹配星火ASR要求）
    RATE = 16000      # 固定16k采样率
    CHANNELS = 1      # 单声道
    FORMAT = pyaudio.paInt16  # 16位深
    FRAME_SIZE = 640  # 20ms/帧（16000*20ms*16bit*1ch/8=640字节）
    CHUNK = 1024      # 缓冲区大小
    
    # 初始化PyAudio
    audio = pyaudio.PyAudio()
    
    # 打开音频流
    stream = audio.open(format=FORMAT,
                        channels=CHANNELS,
                        rate=RATE,
                        input=True,
                        frames_per_buffer=CHUNK)
    
    print("开始录音")
    
    # 存储音频帧
    frames = []
    
    # 计算需要读取的数据块数量
    # 每秒需要读取 RATE/CHUNK 个块
    total_frames = int(RATE / CHUNK * duration)
    
    # 录制音频
    for i in range(total_frames):
        data = stream.read(CHUNK)
        frames.append(data)
    
    print("录音结束.")
    
    # 关闭音频流
    stream.stop_stream()
    stream.close()
    audio.terminate()
    
    # 确保temp_audio目录存在
    temp_audio_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'temp_audio')
    if not os.path.exists(temp_audio_dir):
        os.makedirs(temp_audio_dir)
    
    # 保存WAV文件
    wav_filename = os.path.join(temp_audio_dir, f"{filename}.wav")
    wf = wave.open(wav_filename, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(audio.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()
    
    print(f"🔊 声纹样本已保存到文件: {wav_filename}")
    return wav_filename


"""
    将WAV文件转换为MP3格式
    Args:
        wav_file_path: WAV文件路径
    Returns:
        str: MP3文件路径
"""
def convert_wav_to_mp3(wav_file_path):
    # 加载WAV文件
    audio = AudioSegment.from_wav(wav_file_path)
    
    # 构造MP3文件路径
    mp3_filename = wav_file_path.replace('.wav', '.mp3')
    
    # 导出为MP3格式
    audio.export(mp3_filename, format="mp3")
    
    print(f"✅ 音频已转换为MP3格式并保存: {mp3_filename}")
    return mp3_filename


"""
    录制音频并转换为MP3格式
    Args:
        filename: 文件名（不含扩展名），如果未提供则自动生成
        duration: 录音时长（秒），默认4秒
    Returns:
        tuple: (wav_file_path, mp3_file_path)
"""
def record_and_convert(filename=None, duration=4):

    # 如果没有提供文件名，则生成带时间戳的文件名
    if filename is None:
        filename = f"user_voice_record_{time.strftime('%Y%m%d_%H%M%S')}"
    
    # 录制音频
    wav_file = record_audio(filename, duration)

    # 播放一遍
    from utils.audio_player import play_audio
    play_audio(wav_file)
    
    # 转换为MP3
    mp3_file = convert_wav_to_mp3(wav_file)
    
    return wav_file, mp3_file


"""
    声纹注册流程：录入用户信息并录制音频
    Args:
        db_config: 数据库配置
        duration: 录音时长（秒），默认4秒
    Returns:
        bool: 是否成功注册
"""
def enroll_voiceprint(db_config, duration=4):
    try:
        # 获取用户输入
        user_english_name = input("请输入您的英文名（必填）: ").strip()
        if not user_english_name:
            print("❌ 英文名不能为空！")
            return False
            
        # 检查英文名是否已存在
        from Impl.wav_impl import WavImpl
        with WavImpl(db_config) as wav_impl:
            if wav_impl.check_user_english_name_exists(user_english_name):
                print(f"❌ 英文名 '{user_english_name}' 已存在，请选择其他名称！")
                return False
        
        user_chinese_name = input("请输入您的中文名（选填，直接回车跳过）: ").strip()
        if not user_chinese_name:
            user_chinese_name = None
            
        # 用户身份 - 保留您原有的字段
        user_identity = input("请输入您的用户身份（选填，直接回车跳过）: ").strip()
        if not user_identity:
            user_identity = None
            
        # 使用TTS播报开始录音提示
        from utils.tts_player import speak_text
        speak_text("请按照提示进行声纹注册，请确保录音声音大而自然！！！。", blocking=True)
        speak_text("请在听到提示后开始说话，录制将自动开始", blocking=True)
        time.sleep(1)
        speak_text("开始录音", blocking=True)
        
        # 录制音频并转换为MP3
        wav_file_path, mp3_file_path = record_and_convert(f"voiceDB_{user_english_name}", duration)
        
        # 读取MP3文件数据用于存储
        with open(mp3_file_path, 'rb') as f:
            file_data = f.read()
        
        # 保存到数据库
        from Mapper.wav_mapper import WavFile
        wav_file = WavFile(
            user_english_name=user_english_name,
            user_chinese_name=user_chinese_name,
            user_identity=user_identity,
            audio_type='1',  # 上传声纹库
            file_data=file_data,
            upload_time=time.strftime('%Y-%m-%d %H:%M:%S')
        )
        
        inserted_id = None
        with WavImpl(db_config) as wav_impl:
            inserted_id = wav_impl.insert_wav(wav_file)
            
        print(f"✅ 声纹注册成功！欢迎 {user_english_name}")
        
        # 获取自增ID后上传到声纹库
        if inserted_id:
            # 调用声纹库API上传
            from Mapper.voiceDB_mapper import req_url
            from config import VOICE_APP_ID, VOICE_API_KEY, VOICE_API_SECRET, VOICE_DB_GROUP_NAME, VOICE_DB_GROUP_ID
            
            response = req_url(
                api_name='createFeature',
                APPId=VOICE_APP_ID,
                APIKey=VOICE_API_KEY,
                APISecret=VOICE_API_SECRET,
                file_path=mp3_file_path,
                group_name=VOICE_DB_GROUP_NAME,
                group_id=VOICE_DB_GROUP_ID,
                user_id=str(inserted_id),  # 使用数据库自增ID作为声纹用户ID
                user=user_english_name
            )
            print(f"🔊 声纹库上传结果: {response}")
        
        # 询问是否进行测试
        test_choice = input("是否需要进行声纹配对测试？(y/n): ").strip().lower()
        if test_choice == 'y':
            print("开始声纹配对测试...")
            # 录制测试音频
            test_wav_path, test_mp3_path = record_and_convert(f"voiceDB_{user_english_name}_test", duration)
            
            # 调用声纹识别1:N接口进行测试
            from Mapper.voiceDB_mapper import req_url
            from config import VOICE_APP_ID, VOICE_API_KEY, VOICE_API_SECRET, VOICE_DB_GROUP_NAME, VOICE_DB_GROUP_ID
            
            response = req_url(
                api_name='searchFea',
                APPId=VOICE_APP_ID,
                APIKey=VOICE_API_KEY,
                APISecret=VOICE_API_SECRET,
                file_path=test_mp3_path,
                group_name=VOICE_DB_GROUP_NAME,
                group_id=VOICE_DB_GROUP_ID,
                user_id=None,
                user=user_english_name
            )
            print(f"🔊 声纹配对测试结果: {response}")
        
        return True
        
    except Exception as e:
        print(f"❌ 声纹注册失败: {str(e)}")
        return False


if __name__ == "__main__":
    enroll_voiceprint(DB_CONFIG, duration=4)
